package pl.polsl.mmm.projectcomm.data;

import java.io.Serializable;

/**
 * Created by Maciek on 2014-11-02.
 */
public class vec3 implements Serializable {
    public float x, y, z;

    private static vec4 i = new vec4(),
            t = new vec4(),
            f = new vec4();
    private static vec3 temp = new vec3();

    public vec3(vec3 copyVec) {
        x = copyVec.x;
        y = copyVec.y;
        z = copyVec.z;
    }

    public vec3() {
        x = y = z = 0f;
    }

    public vec3(float x, float y, float z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }
    /**************METODY**************/
    public void copy(vec3 v1) {
        this.x = v1.x;
        this.y = v1.y;
        this.z = v1.z;
    }

    /** Dodanie innego wektora do już istniejącego */
    public void add(vec3 v) {
        x = x + v.x;
        y = y + v.y;
        z = z + v.z;
    }
    /** Dodanie wartości bezpośrednio do składowych  */
    public void add(float x, float y, float z) {
        this.x += x;
        this.y += y;
        this.z += z;
    }
    /** Iloczyn skalarny wektorów 3-elem */
    public float dotProduct(vec3 other) {
        return x * other.x
                + y * other.y
                + z * other.z;
    }
    /** Mnożenie wektora przez skalar (skalowanie) */
    public void scale(float f) {
        x *= f;
        y *= f;
        z *= f;
    }
    /** Liczenie długości wektora (pierwiastek z iloczynu skalarnego)*/
    public float length() {
        return (float)Math.sqrt(x*x+y*y+z*z);
    }

    public float length_2() {
        return x*x+y*y+z*z;
    }
    /** Normalizacja wektora */
    public void normalize() {
        float l = length();
        if(l!=0f) {
            float m = 1.0f / l;
            x *= m;
            y *= m;
            z *= m;
        }
    }
    /** Wyliczanie odwrotności wektora */
    public void invert() {
        x = -x;
        y = -y;
        z = -z;
    }

    /** Dodawanie wektorów 3-elem. */
    public void add(vec3 v0, vec3 v1) {
        x = v0.x + v1.x;
        y = v0.y + v1.y;
        z = v0.z + v1.z;
    }
    /** Odejmowanie wektorów 3-elem. */
    public void diff(vec3 v0, vec3 v1) {
        x = v0.x - v1.x;
        y = v0.y - v1.y;
        z = v0.z - v1.z;
    }
    /** Odległość między wektorami 3-elem */
    public float dist(vec3 v0, vec3 v1) {
        temp.diff(v0,v1);
        return i.length();
    }
    /** Iloczyn wektorowy wektorów 3-elem */
    public void crossProduct(vec3 v1, vec3 v2) {
        x = (v1.y * v2.z) - (v1.z * v2.y);
        y = (v1.z * v2.x) - (v1.x * v2.z);
        z = (v1.x * v2.y) - (v1.y * v2.x);
    }

    /**Obrót wektora 3-elem , wektorem 4-elementowym */
    public void rotateVec4( vec3 v0, vec4 v1 )
    {
        i.conjugate(v1);
        i.normalize();
        t.multiplyVec3( v1, v0 );
        f.multiplyVec4( t, i );
        x = f.x;
        y = f.y;
        z = f.z;
    }
    /** Liniowa interpolacja pomiędzy 2 wektorami.
     * Zmienna t oznacza %-towy udział jednego i drugiego wektora.
     * t == 1f oznacza 100% udział wektora v1 i 0% wektora v0
     * t == 0f oznacza 100% udział wektora v0 i 0% wektora v1
     * t == 0.5f oznacza 50% wartości wektora v1 i 50% wartości wektora v0
     * */
    public void lerp (vec3 v0, vec3 v1, float t) {
        if (t == 1f) {
            this.copy(v1);
            return;
        } else if (t==0f) {
            this.copy(v0);
            return;
        }
        x = v0.x + t * (v1.x - v0.x);
        y = v0.y + t * (v1.y - v0.y);
        z = v0.z + t * (v1.z - v0.z);
    }
    /** Porównanie wektora z innym. Zwraca true jeśli są identyczne*/
    public static boolean vec3Compare(vec3 v0, vec3 v1) {
        if(v0.x==v1.x && v0.y==v1.y && v0.z==v1.z) {
            return true;
        }
        else
            return false;
    }

    public static vec3 calculatePosition(vec3 center, vec3 currentPos, vec3 line ) {
        temp.diff(center,currentPos);
        float R = (float)Math.sqrt(temp.x * temp.x + temp.z * temp.z);
        float c = (-1)*R*R;
        float a = (line.x - center.x)*(line.x - center.x) + (line.z - center.z)*(line.z - center.z);
        float t = ((float)Math.sqrt(-4f*a*c)) / (2*a);
        float newX = (line.x-center.x) * t + center.x;
        float newZ = (line.z-center.z) * t + center.z;

        return new vec3(newX,center.y,newZ);
    }

    public static float twoDimensAngleBetween(vec3 v1,vec3 v2) {
        v1.normalize();
        v2.normalize();
        //float dot = v1.x * v2.x + v1.z * v2.z;

        // return (float) Math.acos(dot);
        return (float)Math.atan2(v2.y,v2.x) - (float)Math.atan2(v1.y,v1.x);
    }

    public static vec3 rotateIn2D (vec3 center, vec3 point , float angle) {
        float newX = center.x + (point.x-center.x)* (float)Math.cos(angle) - (point.z-center.z)*(float)Math.sin(angle);
        float newY = center.z + (point.x-center.x)* (float)Math.sin(angle) + (point.z-center.z)* (float)Math.cos(angle);
        return new vec3(newX,point.y,newY);
    }
}
